package com.hyts.infodb.utils;

import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.Properties;

/**
 * <pre>
  * 智能配置文件读取类管理池，通过该管理池获得的配置文件的属性值
  * 可以自动随着配置文件的更改而刷新，不需要重启应用服务。
  * 使用实例：
 * [1]:比如配置文件application.properties在目录src下使用如下方式。
 * <p>
 * 	ConfigFile cfg = ConfigFileFactory.getInstance().get("application");
 * 	String value = cfg.getValue("value");
 * </p>
 * [2]:配置文件boss.properties和类com.maywide.common.SessionUtil在同一目录下，可以使用如下方式
 * <p>
 * 	ConfigFile cfg = ConfigFileFactory.getInstance().get("boss", SessionUtil.class);
 * 	String value = cfg.getValue("value");
 * </p>
 * [3]:配置文件smp.properties在包com.maywide.common.config,则可使用如下方式。
 * <p>
 * ConfigFile cfg = ConfigFileFactory.getInstance().get("smp", "/com/maywide/common/config/");
 * 	String value = cfg.getValue("value");
 * </p>
 * </pre>
 * 
 * @author luoxian
 * @since Jul 10, 2008 8:49:55 AM
 * @version 1.0
 */
public class ConfigFileFactory {
	private static ConfigFileFactory instance = null;
	private final String extendName = ".properties"; // 默认配置文件格式
	private HashMap<String, ConfigFile> hashMap = new HashMap<String, ConfigFile>();

	private ConfigFileFactory() {
	}

	public static synchronized ConfigFileFactory getInstance() {
		if (instance == null) {
			instance = new ConfigFileFactory();
		}
		return instance;
	}

	/**
	 * 该函数表示配置文件在根目录，及在classes目录下
	 * 
	 * @param fileName
	 * @return
	 * @throws Exception
	 */
	public ConfigFile get(String fileName) throws Exception {
		ConfigFile file = (ConfigFile) hashMap.get(fileName);
		if (file == null) {
			ConfigFile newFile;
			newFile = new ConfigFile(fileName + extendName);
			hashMap.put(fileName, newFile);
			return newFile;
		}
		return file;
	}

	/**
	 * 该函数表示配置文件和resendClass这个类具有相同的目录
	 * 
	 * @param fileName
	 * @param presentClass
	 * @return
	 * @throws Exception
	 */
	public ConfigFile get(String fileName, Class<?> presentClass) throws Exception {
		ConfigFile file = (ConfigFile) hashMap.get(fileName);
		if (file == null) {
			ConfigFile newFile = new ConfigFile(fileName + extendName,
					presentClass);
			hashMap.put(fileName, newFile);
			return newFile;
		}
		return file;
	}

	/**
	 * 该函数读取配置文件，文件目录由参数path指定<br>
	 * 
	 * <pre>
	 * 例如：配置文件config.properties在包com.maywide.common.test包下
	 * 则传入的path参数为  &quot;/com/maywide/common/test/&quot;
	 * </pre>
	 * 
	 * @param fileName
	 * @param packageName
	 * @return
	 * @throws Exception
	 */
	public ConfigFile get(String fileName, String packageName) throws Exception {
		ConfigFile file = (ConfigFile) hashMap.get(fileName);
		if (file == null) {
			ConfigFile newFile = new ConfigFile(fileName + extendName,
					packageName);
			hashMap.put(fileName, newFile);
			return newFile;
		}
		return file;
	}

	public int size() {
		return hashMap.size();

	}

	/**
	 * <pre>
	 * 	该配置文件读取类在程序运行过程如果配置文件更改了的话
	 * 	会自动重新装载配置文件，不用停应用服务
	 * </pre>
	 *
	 * @author luoxian
	 * @since Jun 24, 2008 5:19:22 PM
	 * @version 1.0
	 */
	public static class ConfigFile {

		private Properties properties;
		private long configLastModifiedTime; // 上次修改时间
		private String config_file_name; // ="application.properties";
		private String config_file_path;

		public ConfigFile() {
		}

		/**
		 *
		 * 该构造函数表示配置文件和resendClass这个类具有相同的目录
		 *
		 * @param configFileName
		 * @param presentClass
		 * @throws Exception
		 */
		public ConfigFile(String configFileName, Class<?> presentClass)
				throws Exception {
			this(configFileName, getPathByPackage(presentClass));
		}

		/**
		 * 该构造函数表示配置文件在根目录，及在classes目录下
		 *
		 * @param configFileName
		 * @throws Exception
		 */
		public ConfigFile(String configFileName) throws Exception {
			this(configFileName, "");
		}

		/**
		 * 该构造函数读取配置文件，文件目录由参数path指定<br>
		 *
		 * <pre>
		 * 	例如：配置文件config.properties在包com.maywide.gcost.test包下
		 * 	则传入的path参数为  "/com/maywide/gcost/test/"
		 * </pre>
		 *
		 * @param configFileName
		 * @param path
		 * @throws Exception
		 */
		public ConfigFile(String configFileName, String path) throws Exception {
			setConfig_file_name(configFileName);
			setConfig_file_path(path);
			properties = loadConfigFile(configFileName);
		}

		private Properties loadConfigFile(String configFileName) throws Exception {
			File cfile = getConfigFile(config_file_name, config_file_path);
			if (configLastModifiedTime != 0L
					&& cfile.lastModified() <= configLastModifiedTime) {
				return properties;
			}
			configLastModifiedTime = cfile.lastModified();
			try {
				InputStream in = new FileInputStream(getConfigFile(
						config_file_name, config_file_path));
				properties = new Properties();
				properties.load(in);
				in.close();
			} catch (FileNotFoundException ex) {
				throw new Exception(ex.getMessage());
			} catch (IOException ex) {
				throw new Exception(ex.getMessage());
			}
			return properties;
		}

		private void setConfig_file_path(String config_file_path) {
			this.config_file_path = config_file_path;
		}

		private String getConfig_file_name() {
			return config_file_name;
		}

		private void setConfig_file_name(String config_file_name) {
			this.config_file_name = config_file_name;
		}

		/**
		 * 传入的样子为包路径 例如：path="/com/first/second/"
		 *
		 * @param filename
		 * @param path
		 * @return
		 */
		private File getConfigFile(String filename, String path)
				throws FileNotFoundException {
			URL url = null;
			if (path == null || path.length() == 0) {
				url = ConfigFile.class.getResource("/" + filename); // 放在根目录下
			} else
				url = ConfigFile.class.getResource(path + filename); // 放在类的目录下
			if (url == null)
				throw new FileNotFoundException(path + filename + "文件没有找到");
			File file = new File(url.getPath().replaceAll("%20", " "));
			if (file.isFile() && file.exists() && file.canRead())
				return file;
			return null;
		}

		private static String getPathByPackage(Class<?> presentClass) {
			Package p = presentClass.getPackage();
			// System.out.println(p.getName());
			String path = p.getName().replaceAll("\\.", "/");
			return "/" + path + "/";
		}

		/**
		 * 返回对应的值
		 *
		 * @param name
		 * @return
		 */
		public String getValue(String name) {
			try {
				properties = loadConfigFile(getConfig_file_name());
				return properties.getProperty(name);
			} catch (Exception e) {
				return null;
			}
		}

		/**
		 * 返回一个对应的值，如果配置文件中没有或定义为空，则返回默认值
		 *
		 * @param name
		 * @param defaultValue
		 *            默认值
		 * @return
		 */
		/*
		 * public String getValueByName(String name, String defaultValue) { try {
		 * properties = loadConfigFile(getConfig_file_name()); String result =
		 * properties.getProperty(name); if (result == null ) result = defaultValue;
		 *
		 * return result ; } catch (Exception e) { return null; } }
		 */

		public String getValue(String name, String defaultValue) {
			try {
				properties = loadConfigFile(getConfig_file_name());
				String result = properties.getProperty(name);
				if (result == null)
					result = defaultValue;

				return result;
			} catch (Exception e) {
				return null;
			}
		}

		/*public static void main(String[] args) throws Exception {
			// ConfigFile f = new ConfigFile("application.properties");
			ConfigFile f = new ConfigFile("sms.properties", "/com/maywide/common/");
			System.out.println(f.getValue("hello"));
			for (int i = 0; i < 10; i++) {
				try {
					Thread.sleep(3000);
				} catch (Exception e) {
				}
				System.out.println(f.getValue("shit"));
			}
		}*/
	}
}
